package com.fezz.boot.rpc.registry;

import com.fezz.boot.rpc.protocol.InvokerProto;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.extern.log4j.Log4j2;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 注册处理类
 *
 * @author muyun
 * @version 1.0.0
 * @since 2020/7/6
 */
@Log4j2
public class RegistryHandler extends ChannelInboundHandlerAdapter {

    private final List<String> classNames = new ArrayList<>();
    private final Map<String, Object> registryMap = new ConcurrentHashMap<>();

    public RegistryHandler() {
        scannerClass("com.fezz.boot.rpc.service");
        doRegistry();
    }

    // 注册
    private void doRegistry() {
        if (classNames.isEmpty()) {
            return;
        }

        for (String className : classNames) {
            try {
                Class<?> clazz = Class.forName(className);
                Class<?>[] interfaces = clazz.getInterfaces();
                Class<?> i = interfaces[0];
                String serviceName = i.getName();
                registryMap.put(serviceName, clazz.newInstance());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    // 扫描
    private void scannerClass(String packageName) {

        URL url = this.getClass().getClassLoader().getResource(packageName.replaceAll("\\.", "/"));
        assert url != null;
        File classPath = new File(url.getFile());
        File[] files = classPath.listFiles();
        for (File f : files) {
            if (f.isDirectory()) {
                scannerClass(packageName + "." + f.getName());
            } else {
                classNames.add(packageName + "." + f.getName().replaceAll(".class", ""));
            }
        }
        log.info("classNames : {}", classNames);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        Object response = new Object();
        InvokerProto request = (InvokerProto) msg;
        if (registryMap.containsKey(request.getClassName())) {
            Object service = registryMap.get(request.getClassName());
            Method method = service.getClass().getMethod(request.getMethodName(), request.getParams());
            response = method.invoke(service, request.getValues());
        }
        log.info("server data : {}", response);
        ctx.writeAndFlush(response + "\n");
        ctx.close();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
    }
}
